/**
 * 
 */
package hanto.studentdlally.gamma;

import hanto.common.HantoException;
import hanto.common.HantoGame;
import hanto.studentdlally.common.Coordinate;
import hanto.studentdlally.common.HantoBoard;
import hanto.studentdlally.common.HantoPiece;
import hanto.util.HantoCoordinate;
import hanto.util.HantoPieceType;
import hanto.util.HantoPlayerColor;
import hanto.util.MoveResult;

/**
 * @author Doug Lally
 * @version Gamma
 *
 */
public class GammaHantoGame implements HantoGame {

	private HantoPlayerColor nextPlayerColor;
	private int nextMoveNumber;
	private boolean isGameOver;
	private int numBlueSparrows;
	private int numRedSparrows;
	private HantoPiece blueButterfly, redButterfly;
	private final HantoBoard board;

	/**
	 * Default Constructor
	 */
	public GammaHantoGame(){
		nextPlayerColor = HantoPlayerColor.BLUE;
		board = new HantoBoard();
		nextMoveNumber = 1;
		isGameOver = false;
		numBlueSparrows = numRedSparrows = 0;
		blueButterfly = redButterfly = null;
	}

	/* (non-Javadoc)
	 * @see hanto.common.HantoGame#initialize(hanto.util.HantoPlayerColor)
	 */
	@Override
	public void initialize(HantoPlayerColor firstPlayer){
		nextPlayerColor = firstPlayer;

	}

	/* (non-Javadoc)
	 * @see hanto.common.HantoGame#makeMove(hanto.util.HantoPieceType, hanto.util.HantoCoordinate, hanto.util.HantoCoordinate)
	 */
	@Override
	public MoveResult makeMove(HantoPieceType pieceType, HantoCoordinate from,
			HantoCoordinate to) throws HantoException {
		if(!isValidMove(pieceType, from, to)){
			throw new HantoException("Invalid Move");
		}
		// Move the piece if needed
		if(from != null){
			board.movePiece(from, to);

		}
		//Play the piece
		else{
			board.playPiece(new HantoPiece(nextPlayerColor, pieceType, new Coordinate(to.getX(), to.getY())));
			// If this was a sparrow, keep track of the number played
			if(pieceType == HantoPieceType.SPARROW){
				if(nextPlayerColor == HantoPlayerColor.BLUE){
					numBlueSparrows++;
				}
				else{
					numRedSparrows++;
				}
			}
		}
		// Increment move number and swap next player color
		nextMoveNumber++;
		if(nextPlayerColor == HantoPlayerColor.BLUE){
			nextPlayerColor = HantoPlayerColor.RED;
		}
		else{
			nextPlayerColor = HantoPlayerColor.BLUE;
		}

		// See if the game is over
		blueButterfly = board.findBlueButterfly();
		redButterfly = board.findRedButterfly();

		if(board.isSurrounded(blueButterfly) && board.isSurrounded(redButterfly)){
			isGameOver = true;
			return MoveResult.DRAW;
		}
		if(board.isSurrounded(blueButterfly)){
			isGameOver = true;
			return MoveResult.RED_WINS;
		}
		else if(board.isSurrounded(redButterfly)){
			isGameOver = true;
			return MoveResult.BLUE_WINS;
		}

		//See if we are out of moves
		if(nextMoveNumber == 21){
			isGameOver = true;
			return MoveResult.DRAW;
		}

		return MoveResult.OK;
	}

	/**
	 * @param pieceType piece type being played
	 * @param from origin of piece (null if not played yet)
	 * @param to destination of piece
	 * @return true if valid, false otherwise
	 */
	private boolean isValidMove(HantoPieceType pieceType, HantoCoordinate from,
			HantoCoordinate to) {
		if(isGameOver){
			return false;
		}
		// We can only play butterflies or sparrows
		if(pieceType != HantoPieceType.BUTTERFLY && pieceType != HantoPieceType.SPARROW){
			return false;
		}
		// Only butterfly can move
		if(from != null){
			if(pieceType != HantoPieceType.BUTTERFLY){
				return false;
			}
			// Make sure we are moving from valid location (correct color and piece type, adjacent space)
			if(board.getPieceByCoordinates(from) == null ||
					board.getPieceByCoordinates(from).getType() != HantoPieceType.BUTTERFLY ||
					board.getPieceByCoordinates(from).getColor() != nextPlayerColor ||
					!Coordinate.generateCoordinate(from).isAdjacent(to)){
				return false;
			}
			// Check if destination is occupied
			if(board.getPieceByCoordinates(to) != null){
				return false;
			}
			// Pretend to move the piece, Check if moving this piece would seperate the board
			board.movePiece(from, to);
			boolean wouldBeConnected;
			wouldBeConnected = board.isConnected();
			// Move the piece back
			board.movePiece(to, from);

			if(!wouldBeConnected){
				return false;
			}
		}
		//First move must be at 0,0
		if(nextMoveNumber == 1){
			return (to.getX() == 0 && to.getY() == 0);
		}
		//If this is a player's fourth turn, then they must have played or be playing the butterfly
		if(nextMoveNumber == 7 || nextMoveNumber == 8){
			if(pieceType != HantoPieceType.BUTTERFLY && !hasPlayedButterfly(nextPlayerColor)){
				return false;
			}
		}
		// Can't play a second butterfly
		if(pieceType == HantoPieceType.BUTTERFLY && hasPlayedButterfly(nextPlayerColor) && from == null){
			return false;
		}
		//Must not occupy the same spot as another piece
		if(board.getPieceByCoordinates(to) != null){
			return false;
		}
		// Cannot play more than 5 sparrows
		if(pieceType == HantoPieceType.SPARROW){
			if(nextPlayerColor == HantoPlayerColor.BLUE && numBlueSparrows >= 5){
				return false;
			}
			else if(nextPlayerColor == HantoPlayerColor.RED && numRedSparrows >= 5){
				return false;
			}
		}
		// Must be adjacent to a played piece

		if(board.isAdjacentToAny(to)){
			return true;
		}
		// Otherwise, it is not adjacent
		return false;
	}




	private boolean hasPlayedButterfly(HantoPlayerColor color) {
		if(color == HantoPlayerColor.BLUE){
			return blueButterfly != null;
		}
		else{
			return redButterfly != null;
		}
	}

	/* (non-Javadoc)
	 * @see hanto.common.HantoGame#getPrintableBoard()
	 */
	@Override
	public String getPrintableBoard() {
		return board.getPrintableBoard();
	}


	/**
	 * @return the color of the next player
	 */
	public HantoPlayerColor getNextPlayerColor() {
		return nextPlayerColor;
	}

}
